#ifndef __LDX_SMESH_H_INCLUDE__
#define __LDX_SMESH_H_INCLUDE__
#include "LDXConfig.h"
#include "IMesh.h"
#include "IMeshBuffer.h"

namespace ldx
{
	namespace scene
	{
		//! Simple implementation of the IMesh interface.
		class SMesh : public IMesh
		{
		public:
			//! constructor
			SMesh()
			{
#ifdef _DEBUG
				setDebugName("SMesh");
#endif
			}

			//! destructor
			virtual ~SMesh()
			{
				// drop buffers
				for (mt::uint i = 0; i<MeshBuffers.size(); ++i)
					MeshBuffers[i]->drop();
			}

			//! clean mesh
			virtual void clear()
			{
				for (mt::uint i = 0; i<MeshBuffers.size(); ++i)
					MeshBuffers[i]->drop();
				MeshBuffers.clear();
				BoundingBox.reset(0.f, 0.f, 0.f);
			}


			//! returns amount of mesh buffers.
			virtual mt::uint getMeshBufferCount() const
			{
				return (mt::uint)MeshBuffers.size();
			}

			//! returns pointer to a mesh buffer
			virtual IMeshBuffer* getMeshBuffer(mt::uint nr) const
			{
				return MeshBuffers[nr];
			}

			//! returns a meshbuffer which fits a material
			/** reverse search */
			virtual IMeshBuffer* getMeshBuffer(const render::SMaterial & material) const
			{
				for (int i = (int)MeshBuffers.size() - 1; i >= 0; --i)
				{
					if (material == MeshBuffers[i]->getMaterial())
						return MeshBuffers[i];
				}

				return 0;
			}

			//! returns an axis aligned bounding box
			virtual const mt::aabbox3df& getBoundingBox() const
			{
				return BoundingBox;
			}

			//! set user axis aligned bounding box
			virtual void setBoundingBox(const mt::aabbox3df& box)
			{
				BoundingBox = box;
			}

			//! recalculates the bounding box
			void recalculateBoundingBox()
			{
				if (MeshBuffers.size())
				{
					BoundingBox = MeshBuffers[0]->getBoundingBox();
					for (mt::uint i = 1; i<MeshBuffers.size(); ++i)
						BoundingBox.addInternalBox(MeshBuffers[i]->getBoundingBox());
				}
				else
					BoundingBox.reset(0.0f, 0.0f, 0.0f);
			}

			//! adds a MeshBuffer
			/** The bounding box is not updated automatically. */
			void addMeshBuffer(IMeshBuffer* buf)
			{
				if (buf)
				{
					buf->grab();
					MeshBuffers.push_back(buf);
				}
			}

			//! sets a flag of all contained materials to a new value
			virtual void setMaterialFlag(render::E_MATERIAL_FLAG flag, bool newvalue)
			{
				for (mt::uint i = 0; i<MeshBuffers.size(); ++i)
					MeshBuffers[i]->getMaterial().setFlag(flag, newvalue);
			}

			//! set the hardware mapping hint, for driver
			virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX)
			{
				for (mt::uint i = 0; i<MeshBuffers.size(); ++i)
					MeshBuffers[i]->setHardwareMappingHint(newMappingHint, buffer);
			}

			//! flags the meshbuffer as changed, reloads hardware buffers
			virtual void setDirty(E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX)
			{
				for (mt::uint i = 0; i<MeshBuffers.size(); ++i)
					MeshBuffers[i]->setDirty(buffer);
			}

			//! The meshbuffers of this mesh
			std::vector<IMeshBuffer*> MeshBuffers;

			//! The bounding box of this mesh
			mt::aabbox3df BoundingBox;
		};
	}
}


#endif//! __LDX_SMESH_H_INCLUDE__